package com.woniu.shiro_config;

import com.auth0.jwt.exceptions.JWTVerificationException;
import com.woniu.entity.RbacManager;
import com.woniu.service.RbacManagerService;
import com.woniu.service.RbacPermService;
import com.woniu.service.RbacRoleService;
import com.woniu.utils.JWTUtils;
import com.woniu.utils.MyJsonWebToken;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.Set;

/**
 * 自定义域
 *
 * @author WenXin
 * @version 1.0
 * @description: TODO
 * @date 2022/9/6 13:53
 */
@Configuration
public class MyJWTRealm extends AuthorizingRealm {

    private final String REALMNAME = "MyJWTRealm";
    @Autowired
    RbacRoleService rbacRoleService;
    @Autowired
    RbacPermService rbacPermService;
    @Autowired(required = false)
    RbacManagerService rbacManagerService;
    //整合redis模板
    @Autowired
    RedisTemplate redisTemplate;

    //配置token支持
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof MyJsonWebToken;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String username = principals.getPrimaryPrincipal() + "";
        //通过登录的用户名，去查询权限信息
        Set<String> rbacRoles = rbacRoleService.findOneByUserName(username);
        //set集合存放的role角色名 将其放入simpleAuthorizationInfo中
        //设置角色名
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(rbacRoles);
        //查询当前角色对应的权限
        Set<String> permBySetRoles = rbacPermService.findPermBySetRoles(username);
        //将权限信息存放进 simpleAuthorizationInfo
        //设置权限名
        simpleAuthorizationInfo.setStringPermissions(permBySetRoles);
        return simpleAuthorizationInfo;
    }

    /**
     * 认证方法的开发！
     *
     * @param authenticationToken
     * @return org.apache.shiro.authc.AuthenticationInfo
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String token = authenticationToken.getCredentials() + "";
        //优化后的版本，直接通过查询redis数据来进行验证，不用去查数据库了
        RbacManager rbacManager = (RbacManager) redisTemplate.opsForValue().get(token);

        //解析token拿到用户名
//        String username = JWTUtils.getUsername(token);
        if (rbacManager == null) {
            throw new AuthenticationException("token中无账号！");
        }
        //说明这个username是可以用的，因为token没有过期,如果用户在前端修改了密码！需不需要重新跳回登录页面？
        //上述代码有一个问题，如果密码改了，但是这个token没过期，也就是说，依然是token有效，认证通过的！
//        RbacManager rbacManager = rbacManagerService.findOneByName(username);
        try {
            //进行过期校验和防篡改校验, 只有一个结果，如果不是true则直接抛出异常,jwt的校验异常
            JWTUtils.verify(token, rbacManager.getAccount(), rbacManager.getPassword());
        } catch (JWTVerificationException e) {
            //转换封装一下，变成认证异常
            throw new AuthenticationException(e.getMessage());
        }
        return new SimpleAuthenticationInfo(rbacManager.getAccount(), token, REALMNAME);
    }
}
